using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;

public class UnityInput
{
    public static readonly int glossyEnvironmentColor = Shader.PropertyToID("_GlossyEnvironmentColor");
    public static readonly int subtractiveShadowColor = Shader.PropertyToID("_SubtractiveShadowColor");

    public static readonly int ambientSkyColor = Shader.PropertyToID("unity_AmbientSky");
    public static readonly int ambientEquatorColor = Shader.PropertyToID("unity_AmbientEquator");
    public static readonly int ambientGroundColor = Shader.PropertyToID("unity_AmbientGround");

    public static readonly int time = Shader.PropertyToID("_Time");
    public static readonly int sinTime = Shader.PropertyToID("_SinTime");
    public static readonly int cosTime = Shader.PropertyToID("_CosTime");
    public static readonly int deltaTime = Shader.PropertyToID("unity_DeltaTime");
    public static readonly int timeParameters = Shader.PropertyToID("_TimeParameters");


    const string bufferName = "UnityInput";


    CommandBuffer buffer = new CommandBuffer
    {
        name = bufferName
    };

    ScriptableRenderContext context;

    public void Setup(ScriptableRenderContext context)
    {
        this.context = context;
        SetupShaderTimeValues();
        SetupPerFrameShaderConstants();
        Submit();
    }

    void Submit()
    {
        ExecuteBuffer();
        context.Submit();
    }

    void ExecuteBuffer()
    {
        context.ExecuteCommandBuffer(buffer);
        buffer.Clear();
    }

    void SetupShaderTimeValues()
    {

#if UNITY_EDITOR
        float time = Application.isPlaying ? Time.time : Time.realtimeSinceStartup;
#else
            float time = Time.time;
#endif
        float deltaTime = Time.deltaTime;
        float smoothDeltaTime = Time.smoothDeltaTime;

        float timeEights = time / 8f;
        float timeFourth = time / 4f;
        float timeHalf = time / 2f;

        // Time values
        Vector4 timeVector = time * new Vector4(1f / 20f, 1f, 2f, 3f);
        Vector4 sinTimeVector = new Vector4(Mathf.Sin(timeEights), Mathf.Sin(timeFourth), Mathf.Sin(timeHalf), Mathf.Sin(time));
        Vector4 cosTimeVector = new Vector4(Mathf.Cos(timeEights), Mathf.Cos(timeFourth), Mathf.Cos(timeHalf), Mathf.Cos(time));
        Vector4 deltaTimeVector = new Vector4(deltaTime, 1f / deltaTime, smoothDeltaTime, 1f / smoothDeltaTime);
        Vector4 timeParametersVector = new Vector4(time, Mathf.Sin(time), Mathf.Cos(time), 0.0f);

        buffer.SetGlobalVector(UnityInput.time, timeVector);
        buffer.SetGlobalVector(UnityInput.sinTime, sinTimeVector);
        buffer.SetGlobalVector(UnityInput.cosTime, cosTimeVector);
        buffer.SetGlobalVector(UnityInput.deltaTime, deltaTimeVector);
        buffer.SetGlobalVector(UnityInput.timeParameters, timeParametersVector);
    }

    void SetupPerFrameShaderConstants()
    {
        // When glossy reflections are OFF in the shader we set a constant color to use as indirect specular
        SphericalHarmonicsL2 ambientSH = RenderSettings.ambientProbe;
        Color linearGlossyEnvColor = new Color(ambientSH[0, 0], ambientSH[1, 0], ambientSH[2, 0]) * RenderSettings.reflectionIntensity;
        Color glossyEnvColor = CoreUtils.ConvertLinearToActiveColorSpace(linearGlossyEnvColor);
        buffer.SetGlobalVector(UnityInput.glossyEnvironmentColor, glossyEnvColor);

        // Ambient
        buffer.SetGlobalVector(UnityInput.ambientSkyColor, CoreUtils.ConvertSRGBToActiveColorSpace(RenderSettings.ambientSkyColor));
        buffer.SetGlobalVector(UnityInput.ambientEquatorColor, CoreUtils.ConvertSRGBToActiveColorSpace(RenderSettings.ambientEquatorColor));
        buffer.SetGlobalVector(UnityInput.ambientGroundColor, CoreUtils.ConvertSRGBToActiveColorSpace(RenderSettings.ambientGroundColor));

        // Used when subtractive mode is selected
        buffer.SetGlobalVector(UnityInput.subtractiveShadowColor, CoreUtils.ConvertSRGBToActiveColorSpace(RenderSettings.subtractiveShadowColor));
    }

}
